﻿using HelperFromTheSkeleton.Common;
using HelperFromTheSkeleton.Model.WebSocketModels;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Net.WebSockets;
using System.Reflection;
using System.Text;

namespace HelperFromTheSkeleton.WebSocketCore
{
    public static class WebSocketApplicationBuilderHelper
    {
        public static IApplicationBuilder UseWebSocketsHelper(this IApplicationBuilder app, string handleAssemblyName)
        {
            Assembly ab;
            ab = Assembly.Load($"{handleAssemblyName}");
            var types = ab.GetExportedTypes();
            if (types != null)
            {
                foreach (var val in types)
                {
                    var inteficeTypes = val.GetInterfaces();
                    if (inteficeTypes != null)
                    {
                        var baseHandelType = inteficeTypes.FirstOrDefault(m => m.Name.Contains("IBaseHandle"));
                        if (baseHandelType == null) continue;
                        if (baseHandelType != null)
                        {
                            var eventType = baseHandelType?.GenericTypeArguments.FirstOrDefault(m => m.BaseType?.FullName == typeof(BaseEventModel).FullName);
                            if (eventType == null) continue;
                            WebSocketEventBus eventBus = Config.GetServer<WebSocketEventBus>() ?? throw new InvalidOperationException("Socket总线服务获取失败");
                            eventBus.Band(eventType ?? throw new InvalidOperationException("绑定事件时找不到eventType"), val, baseHandelType ?? throw new InvalidOperationException("绑定事件时找不到baseHandelType"));
                        }
                    }
                }
            }
            app.UseWebSockets(new WebSocketOptions
            {
                KeepAliveInterval = TimeSpan.FromSeconds(2),
            });
            app.Use(async (context, next) =>
            {
                if (context.Request.Path == "/ws")
                {
                    if (context.WebSockets.IsWebSocketRequest)
                    {
                        try
                        {
                            using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
                            await Echo(webSocket);
                        }
                        catch (Exception ex)
                        {
                            var loggerFactory = Config.GetServer<ILoggerFactory>();
                            var logger = loggerFactory?.CreateLogger("SocketError");
                            logger?.LogError(ex, $"{Config.ApplicationCode} Socket服务创建时出错");
                            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
                        }
                    }
                    else
                    {
                        context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    }
                }
                else
                {
                    await next(context);
                }

            });
            return app;
        }

        private static async Task Echo(WebSocket webSocket)
        {
            WebSocketEventBus eventBus = Config.GetServer<WebSocketEventBus>() ?? throw new InvalidOperationException("Socket总线服务获取失败");

            async Task<bool> sendFunc(string m)
            {
                var sendBuffer = Encoding.UTF8.GetBytes(m);
                await webSocket.SendAsync(new ArraySegment<byte>(sendBuffer, 0, 10), WebSocketMessageType.Text, WebSocketMessageFlags.None, CancellationToken.None);
                return true;
            }

            bool isClose() => webSocket.CloseStatus.HasValue;
            async Task closeFunc()
            {
                await webSocket.CloseAsync(webSocket.CloseStatus ?? WebSocketCloseStatus.Empty, webSocket.CloseStatusDescription, CancellationToken.None);
            }
            WebSocketChannelModel socketChannel = new(sendFunc, isClose, closeFunc);
            var buffer = new byte[1024 * 1024];
            try
            {
                WebSocketReceiveResult receiveResult;
                do
                {
                    receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    var data = Encoding.UTF8.GetString(buffer, 0, receiveResult.Count);
                    if (!string.IsNullOrWhiteSpace(data))
                    {
                        await eventBus.Trigger(data, socketChannel);
                    }
                    buffer = new byte[1024 * 1024];
                } while (!receiveResult.CloseStatus.HasValue);
                await socketChannel.Close();
            }
            catch (Exception ex)
            {
                var loggerFactory = Config.GetServer<ILoggerFactory>();
                var logger = loggerFactory?.CreateLogger("WebSocketAccess");
                logger?.LogInformation(ex, "WebSocket断开");
                await socketChannel.Close();
            }
        }
    }
}